use super::room_manager::RoomManager;

use std::{collections::HashMap, sync::Arc};

use serde_derive::{Deserialize, Serialize};
use serde_json::{from_str, json, to_string, Value};
use tracing::{info, warn};

use futures::{SinkExt, Stream, StreamExt};
use tokio::{
    select,
    sync::{mpsc, oneshot},
};
use warp::ws::{Message, WebSocket};

#[derive(Debug)]
pub struct Room {
    name: String,
    password: Option<String>,
}

#[derive(Debug)]
pub enum RoomMsg {
    ToOther { user_id: usize, msg: Value },
    Broadcast { msg: Value },
    Disconnection { user_id: usize },
    // room, user_id, channel
    // Room task 转发信息直接用 string， 具体的序列化和处理交给处理者处理
    NewIn(oneshot::Sender<(Arc<Room>, usize, mpsc::Receiver<Value>)>),
}

#[derive(Serialize)]
enum Response {
    NoRoom,
    NeedPassword,
    WrongPassword,
    WrongPasswordTimesOverLimit,
    YourId { id: usize },
    OneExit { id: usize },
}

// 因为 oneshot::Sender<T> 没有实现 serde::Deserialize, 所以需要这个来过一下
#[derive(Deserialize, Serialize)]
enum Forward {
    ToOther { user_id: usize, msg: Value },
    Broadcast { msg: Value },
}

impl Into<RoomMsg> for Forward {
    fn into(self) -> RoomMsg {
        match self {
            Self::ToOther { user_id, msg } => RoomMsg::ToOther { user_id, msg },
            Self::Broadcast { msg } => RoomMsg::Broadcast { msg },
        }
    }
}

/// 管理单个房间
pub(crate) async fn room_task(
    name: String,
    password: Option<String>,
    self_id: usize,
    mut recevicer: mpsc::Receiver<RoomMsg>,
    manager_sender: mpsc::Sender<super::room_manager::Message>,
) {
    let room = Arc::new(Room { name, password });
    let mut users: HashMap<usize, mpsc::Sender<Value>> = HashMap::new();
    let mut id: usize = 0;

    while let Some(msg) = recevicer.recv().await {
        use RoomMsg::*;
        match msg {
            ToOther { user_id, msg } => {
                let sender = &users[&user_id];
                if let Err(_) = sender.send(msg).await {
                    warn!("room task channel send error");
                }
            }
            Broadcast { msg } => {
                for sender in users.values() {
                    if let Err(_) = sender.send(msg.clone()).await {
                        warn!("room task channel send error");
                    };
                }
            }
            Disconnection { user_id } => {
                users.remove(&user_id);
                for sender in users.values() {
                    if let Err(_) = sender.send(json!(Response::OneExit { id: user_id })).await {
                        warn!("room task channel send error");
                    }
                }
                if users.is_empty() {
                    let ret = manager_sender
                        .send(super::room_manager::Message::Drop(self_id))
                        .await;
                    if let Err(err) = ret {
                        warn!("drop room {} err, err: {}", self_id, err)
                    }
                }
            }
            NewIn(sender) => {
                let new_id = id;
                let (s, r) = mpsc::channel(8);
                users.insert(new_id, s);
                id += 1;
                if let Err(_) = sender.send((room.clone(), new_id, r)) {
                    warn!("room task channel send error");
                }
            }
        }
    }
}

pub async fn room_ws_handle(room_id: usize, socket: WebSocket, room_manager: RoomManager) {
    use RoomMsg::*;
    let manager_tx = super::get(room_id, room_manager).await;

    let (mut ws_tx, mut ws_rx) = socket.split();

    // 如果房间不存在
    if let None = manager_tx {
        if let Err(err) = ws_tx
            .send(Message::text(
                serde_json::to_string(&Response::NoRoom).unwrap(),
            ))
            .await
        {
            todo!()
        }
        return;
    }
    let manager_tx = manager_tx.unwrap();

    // 获取必要信息
    let (room, self_id, mut manager_rx) = {
        let (s, r) = oneshot::channel();
        if let Err(err) = manager_tx.send(NewIn(s)).await {
            todo!()
        }
        r.await.unwrap()
    };

    // 检查密码
    if let Some(password) = room.password.as_ref() {
        if let Err(err) = ws_tx
            .send(Message::text(to_string(&Response::NeedPassword).unwrap()))
            .await
        {
            todo!()
        }
        let mut wrong_password_times: i32 = 0;
        while let Some(Ok(msg)) = ws_rx.next().await {
            if let Ok(msg) = msg.to_str() {
                if msg != password {
                    wrong_password_times += 1;
                    if wrong_password_times == 5 {
                        if let Err(err) = ws_tx
                            .send(Message::text(
                                to_string(&Response::WrongPasswordTimesOverLimit).unwrap(),
                            ))
                            .await
                        {
                            todo!()
                        }
                        return;
                    }
                    if let Err(err) = ws_tx
                        .send(Message::text(to_string(&Response::WrongPassword).unwrap()))
                        .await
                    {
                        todo!()
                    }
                }
            }
        }
    }
    // TODO: send user id
    ws_tx
        .send(Message::text(
            serde_json::to_string(&Response::YourId { id: self_id }).unwrap(),
        ))
        .await
        .unwrap();

    loop {
        // TODO: 这里真的需要么, 可能真的直接转发就行了
        select! {
            msg = ws_rx.next() => match msg {
                Some(Ok(msg)) => {
                    if !msg.is_text() {
                        if msg.is_close() {
                            break;
                        } else {
                            warn!("get ws message is not text and close: {:?}", msg);
                        }
                    }
                    let msg_str = msg.to_str().unwrap();
                    let msg = from_str::<Forward>(msg_str);
                    match msg{
                        Ok(msg) => manager_tx.send(msg.into()).await.unwrap(),
                        Err(err) => warn!("str to forward error, str is: {}", msg_str),
                    }
                }
                Some(Err(err)) => {
                    warn!("error: {:?}", err);
                }
                None => { break } // 这个时候, websocket 断开了
            },
            msg = manager_rx.recv() => {
                if let Some(msg) = msg {
                    if let Err(err) = ws_tx.send(Message::text(to_string(&msg).unwrap())).await {todo!()}
                }
            }
        }
    }

    if let Err(err) = manager_tx.send(Disconnection { user_id: self_id }).await {
        todo!()
    }
}

// Fn, FnOnce, FnMut
// map fold
